//模块加载器
import fs from 'fs'
import {createRequire} from "module";
import tsc from "./tsc"
import sugar from './sugar'
import errorCatch from './errorCatch';
import color from './color';
import Ioc from '../core/Ioc';


//cjs导入器
const Require:any = createRequire(__filename)

const extensions = {
    ".js":cjs,
    ".cjs":cjs,
    ".mjs":mjs,
    ".json":json,
    ".ts":ts
} 

let main = {
    // 创建加载器
    createLoader:(module:object = {})=>{
        Object.keys(module).forEach(e=>{
            if(typeof module[e] === "string"){
                // 加载一次就会被缓存到Ioc容器中
                loader(sugar.path(module[e]))
            }
        })
        return loader
    }
}

if(module) module.exports = main;
export default main;

function Module(id:string){
    return {
        id,
        exports:{},
        loaded:false
    }
}

//核心文件，保存所有控制器的内容，并执行缓存：规则，控制器调用别的模块必须使用绝对路径
//开发中禁用缓存，使路由热启动 //启动加载器
function loader(id:string,bool:boolean=false){
    if(id===undefined) throw new Error("id is not null")

    //查一下缓存
    if(bool===false && Ioc.getClass(id))return Ioc.getClass(id)

    let path = id;
    //判断是否为全局模块,是的话获取该模块的路径并且把路径解析出来
    path = sugar.path(id,{superNumber:3});

    //这有可能是系统模块或第三方模块
    if(!/^[./\\]|^[A-Z]\:/g.test(path)){return Require(path)?.default || Require(path)}

    function isthereAre(filepath:string="",i=0,suffixarr = Object.keys(extensions)){
        if(i>=suffixarr.length){
            console.log(color("红色",path),"模块不存在")
            throw new Error("找不到模块")
        }    
        if(fs.existsSync(filepath) && fs.statSync(filepath)?.isFile()){
            // 添加到缓存中
            let module = Module(filepath);
            if(extensions[filepath.match(/\.[^.\\/]*$/)?.[0]]){
                extensions[filepath.match(/\.[^.\\/]*$/)?.[0]](module)
                Ioc.add(id,filepath,module.exports)
            }else{
                // 使用默认cjs加载
                extensions[".cjs"](module);
                Ioc.add(id,filepath,module.exports);
            }
        }else{
            isthereAre(path+suffixarr[i++],i,suffixarr)
        }
    }
    // 到了这里说明模块存在
    isthereAre(path);
    // 添加缓存
    return Ioc.getClass(id);
}




    
//导入mjs模块的方法
async function mjs(module:any){
    let mj = await import("file://"+module.id);
    module.exports = mj.default ? mj.default : mj;
    module.loaded = true;
}
    
    //导入cjs的方法
function cjs(module:any){
    let data = fs.readFileSync(module.id,"utf8");
    //这是一个模块
    if(/^[ ]*module\.exports/m.test(data) || /^[ ]*exports\./m.test(data)){
        module.exports = CommonJS(module.id);
    }else if(/^[ ]*export default/m.test(data) || /^[ ]*export /m.test(data)){
        module.exports = ECMAScript(module.id);
    }else{
        module.exports = Require(module.id);
    }
    module.loaded = true;
}

//加载这个协议封装的模块
function CommonJS(id:string){
    try{
        let methods = Require(id);
        return methods?.default || methods;
    }catch(err){
        errorCatch(err,'loader.136')
    }
    
}
async function ECMAScript(id:string){
    try{
        let methods = await import(id);
        return methods?.default || methods;
    }catch(err){
        console.log(id)
        errorCatch(err,'loader.145')
    }
}

//导入ts方法
function ts(module:any){
    // 编译好后的js文件位置
    let outdir = module.id.replace(/[\/\\][^/\\]*$/g,"")+"\\.ts";
    let data = tsc(module.id,outdir);
    if(data.includes("err")){console.log(data);throw Error(data)}
    // 引入这个js
    outdir+(module.id.match(/[\/\\][^/\\]*?\./g)?.[0])+"js";
    // 判断是否为全局模块,是的话获取该模块的路径并且把路径解析出来
    module.exports = Require(module.id.match(/\.[^./\\]*/,"")+".js")
    module.loaded = true;
}

function json(module:any){
    module.exports = Require(module.id)
    module.loaded = true
}